﻿using Microsoft.Extensions.Caching.Distributed;
using StackExchange.Redis;

namespace Zhp.Cache
{
    public class RedisCacheService : ICacheService
    {
        private readonly IDistributedCache _cache;
        private readonly IDatabase _db;
        public RedisCacheService(IDatabase db, IDistributedCache cache)
        {
            _cache = cache;
            _db = db;
        }

        public void Dispose()
        {
            throw new NotImplementedException();
        }

        #region 基本操作

        public T Get<T>(string key)
        {
            var bytes = _cache.Get(key);
            return bytes.BytesToObject<T>();
        }

        public async Task<T> GetAsync<T>(string key, CancellationToken token = default)
        {
            var bytes = await _cache.GetAsync(key, token);
            return bytes.BytesToObject<T>();
        }

        public void Set<T>(string key, T value, TimeSpan? expire = null)
        {
            var exp = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = expire };
            _cache.Set(key, value.ObjectToBytes(), exp);
        }

        public async Task SetAsync<T>(string key, T value, TimeSpan? expire = null, CancellationToken token = default)
        {
            var exp = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = expire };
            await _cache.SetAsync(key, value.ObjectToBytes(), exp, token);
        }

        public void Refresh(string key)
        {
            _cache.Refresh(key);
        }

        public async Task RefreshAsync(string key, CancellationToken token = default)
        {
            await _cache.RefreshAsync(key);
        }

        public void Remove(string key)
        {
            _cache.Remove(key);
        }

        public async Task RemoveAsync(string key, CancellationToken token = default)
        {
            await _cache.RemoveAsync(key, token);
        }

        public void Remove(string[] keys)
        {
            foreach (var key in keys)
            {
                _cache.Remove(key);
            }
        }

        public async Task RemoveAsync(string[] keys, CancellationToken token = default)
        {
            foreach (var key in keys)
            {
                await _cache.RemoveAsync(key);
            }
        }

        #endregion

        #region 集合操作

        public List<T> ListRange<T>(string key)
        {
            var value = _db.ListRange(key);
            return value.Any() ? value.Select(x => x.ToString().ToObject<T>()).ToList() : null;
        }

        public void ListRightPush<T>(string key, T value)
        {
            _db.ListRightPush(key, value.ToJson());
        }

        public void ListRightPushArray<T>(string key, T[] values)
        {
            var vals = values.Select(x => (RedisValue)(x.ToJson())).ToArray();
            _db.ListRightPush(key, vals);
        }

        public void ListRemove<T>(string key, T value)
        {
            _db.ListRemove(key, value.ToJson());
        }

        public T ListLeftPop<T>(string key)
        {
            var value = _db.ListLeftPop(key);
            return value.ToString().ToObject<T>();
        }

        #endregion

        #region 哈希对象操作

        public T HashObjGet<T>(string key, string field)
        {
            var value = _db.HashGet(key, field);
            if (value.HasValue)
            {
                return value.ToString().ToJson().ToObject<T>();
            }
            else
            {
                return default(T);
            }
        }

        public T HashObjGet<T>(string key)
        {
            var val = _db.HashGetAll(key);

            if (val.Any())
            {
                var dict = val.ToStringDictionary();
                return dict.DictToObject<T>();
            }
            else
            {
                return default(T);
            }
        }

        public void HashObjSet<T>(string key, T value)
        {
            var dictionary = value.ObjectToDict();

            var hashEntry = dictionary.Select(x => new HashEntry(x.Key, x.Value.ToJson())).ToArray();

            _db.HashSet(key, hashEntry);
        }

        public void HashObjSet(string key, string hashField, object value)
        {
            _db.HashSet(key, hashField, value.ToJson());
        }

        public void HashObjDelete(string key)
        {
            _db.HashDelete(key, _db.HashKeys(key));
        }

        #endregion

        #region 哈希集合操作

        public T HashListGet<T>(string key, object fieldId)
        {
            var value = _db.HashGet(key, fieldId.ToString());

            return value.ToString().ToObject<T>();
        }

        public List<T> HashListGetAll<T>(string key)
        {
            var value = _db.HashGetAll(key);

            var list = new List<T>();
            foreach (var item in value)
            {
                list.Add(item.Value.ToString().ToObject<T>());
            }

            return list;
        }

        public void HashListSet<T>(string key, Func<T, object> fieldFunc, T value)
        {
            _db.HashSet(key, fieldFunc(value).ToString(), value.ToJson());
        }

        public void HashListSet<T>(string key, Func<T, object> fieldFunc, List<T> values)
        {
            var hashEntry = values.Select(x => new HashEntry(fieldFunc(x).ToString(), x.ToJson())).ToArray();
            _db.HashSet(key, hashEntry);
        }

        public void HashListDelete(string key, string field)
        {
            _db.HashDelete(key, field);
        }

        #endregion
    }
}
